home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 January: Mac OS SDK / Dev.CD Jan 00 SDK2.toast / What's New / • What was new 11⁄99 / Sample Code / Interapplication Communication / FinderDragPro / GetIconSuiteFromFinder.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-13  |  12.6 KB  |  502 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FinderDragPro.c
  3.     
  4.     Description:     Sample file illustrating drag and drop techniques for use
  5.                 with file system objects.  This file illustrates how applications
  6.                 can use drag and drop commands in a way compatible with current
  7.                 and past versions of the Finder.
  8.  
  9.     Author:        Pete Gontier
  10.  
  11.     Copyright:     Copyright: © 1999 by Apple Computer, Inc.
  12.                 all rights reserved.
  13.     
  14.     Disclaimer:    You may incorporate this sample code into your applications without
  15.                 restriction, though the sample code has been provided "AS IS" and the
  16.                 responsibility for its operation is 100% yours.  However, what you are
  17.                 not permitted to do is to redistribute the source as "DSC Sample Code"
  18.                 after having made changes. If you're going to re-distribute the source,
  19.                 we require that you make it clear in the source that the code was
  20.                 descended from Apple Sample Code, but that you've made changes.
  21.     
  22.     Change History (most recent first):
  23.     06/09/95    NG    last touched
  24.     08/23/96    PG    stolen from Nitin's old FinderDrag project
  25.     04/21/97    PG    pascal programs can be written in any language
  26. */
  27.     
  28.  
  29. #ifndef __ICONS__
  30. #    include <Icons.h>
  31. #endif
  32.  
  33. #ifndef __ALIASES__
  34. #    include <Aliases.h>
  35. #endif
  36.  
  37. #ifndef __AEREGISTRY__
  38. #    include <AERegistry.h>
  39. #endif
  40.  
  41. #ifndef __GESTALT__
  42. #    include <Gestalt.h>
  43. #endif
  44.  
  45. #ifndef __AEPACKOBJECT__
  46. #    include <AEPackObject.h>
  47. #endif
  48.  
  49. #ifndef __AEOBJECTS__
  50. #    include <AEObjects.h>
  51. #endif
  52.  
  53. #ifndef __ERRORS__
  54. #    include <Errors.h>
  55. #endif
  56.  
  57. #ifndef __TEXTUTILS__
  58. #    include <TextUtils.h>
  59. #endif
  60.  
  61. #ifndef __PROCESSES__
  62. #    include <Processes.h>
  63. #endif
  64.  
  65. #include "GetIconSuiteFromFinder.h"
  66.  
  67. #define require(x,y) do { if (!(x)) goto y; } while (0)
  68.  
  69. AEDesc pFinderTarget;
  70.  
  71. //----------------------------------------------------------------------------
  72. // FinderIsRunning
  73. //
  74. // Walk the Process Mgr list to check if the Finder is running
  75. //----------------------------------------------------------------------------
  76.  
  77. static Boolean FinderIsRunning (void)
  78. {
  79.     OSErr            err;
  80.     ProcessInfoRec    pInfo;
  81.     ProcessSerialNumber    psn;
  82.     Boolean            foundIt;
  83.  
  84.     foundIt = false;
  85.     psn.highLongOfPSN = 0; psn.lowLongOfPSN = kNoProcess;
  86.  
  87.     while ((foundIt == false) && (GetNextProcess(&psn) == noErr)) {
  88.         pInfo.processName         = NULL;
  89.         pInfo.processAppSpec     = NULL;
  90.         pInfo.processInfoLength    = sizeof(ProcessInfoRec);
  91.     
  92.         err = GetProcessInformation(&psn, &pInfo);
  93.     
  94.         if ((err == noErr) 
  95.             && (pInfo.processSignature == 'MACS') 
  96.             && (pInfo.processType == 'FNDR'))
  97.             
  98.             foundIt = true;
  99.     }
  100.     
  101.     return foundIt;
  102. }
  103.  
  104. //----------------------------------------------------------------------------
  105. // HaveScriptableFinder
  106. //
  107. // We have it if the Gestalt bit is set and the Finder is running
  108. //----------------------------------------------------------------------------
  109.  
  110. static Boolean HaveScriptableFinder(void)
  111. {
  112.     long         response;
  113.     Boolean        haveScriptableFinder;
  114.     OSErr        err;
  115.  
  116.     haveScriptableFinder = false;
  117.     
  118.     err = Gestalt(gestaltFinderAttr, &response);
  119.     require(err == noErr, Gestalt);
  120.  
  121.     if ((response & (1 << gestaltOSLCompliantFinder)) && (FinderIsRunning()))
  122.         haveScriptableFinder = true;
  123.  
  124. Gestalt:
  125.     return haveScriptableFinder;
  126. }
  127.  
  128. //----------------------------------------------------------------------------
  129. // SendAppleEvent
  130. //----------------------------------------------------------------------------
  131.  
  132. static OSErr SendAppleEvent(AppleEvent *ae, AppleEvent *reply, AESendMode sendMode)
  133. {
  134.     AppleEvent    throwAwayReply;
  135.     OSErr        err;
  136.  
  137.     if (reply == NULL) {
  138.         err = AESend(ae, &throwAwayReply, sendMode, 
  139.                     kAENormalPriority, kAEDefaultTimeout, NULL, NULL);
  140.         if (err == noErr)
  141.             AEDisposeDesc(&throwAwayReply);
  142.     }
  143.     else
  144.         err = AESend(ae, reply, sendMode, 
  145.                     kAENormalPriority, kAEDefaultTimeout, NULL, NULL);
  146.  
  147.     return err;
  148. }
  149.  
  150.  
  151. //----------------------------------------------------------------------------
  152. // MakeAppleEvent
  153. //----------------------------------------------------------------------------
  154.  
  155. static pascal OSErr MakeAppleEvent
  156.     (AEEventClass aeClass, AEEventID aeID, AEDesc *target, AppleEvent *ae)
  157. {
  158.     OSErr err = noErr;
  159.  
  160.     if (target->dataHandle == nil)
  161.     {
  162.         DescType finderSig = 'MACS';
  163.  
  164.         err = AECreateDesc(typeApplSignature, (Ptr) &finderSig,
  165.             sizeof(DescType), target);
  166.     }
  167.  
  168.     if (!err)
  169.         err = AECreateAppleEvent(aeClass, aeID, target, 
  170.             kAutoGenerateReturnID, kAnyTransactionID, ae);
  171.     
  172.     return err;
  173. }
  174.  
  175. //----------------------------------------------------------------------------
  176. // MakeSpecifierForSelection
  177. //----------------------------------------------------------------------------
  178.  
  179. static OSErr MakeSpecifierForSelection(AEDesc *selectionSpecifier)
  180. {
  181.     OSErr         err;
  182.     DescType     descData;
  183.     AEDesc        keyData, nullDescriptor;
  184.     
  185.     nullDescriptor.descriptorType = typeNull;
  186.     nullDescriptor.dataHandle = NULL;
  187.  
  188.     //
  189.     // Make a descriptor whose type is 'typeType' and whose
  190.     // contents are 'pSelection' (defined in FinderRegistry.h).
  191.     // This descriptor specifies the property of the null container
  192.     // that we are interested in--in this case, the selection.
  193.     //
  194.     descData = pSelection;
  195.     err = AECreateDesc(typeType, (Ptr) &descData, sizeof(DescType), &keyData);
  196.     require(err == noErr, AECreateDesc);
  197.     
  198.     err = CreateObjSpecifier(cProperty, &nullDescriptor, formPropertyID,
  199.                                     &keyData, true, selectionSpecifier);
  200.  
  201. AECreateDesc:
  202.     return err;
  203. }
  204.  
  205. //----------------------------------------------------------------------------
  206. // MakeSpecifierForFile
  207. //----------------------------------------------------------------------------
  208. static pascal OSErr MakeSpecifierForFile(FSSpecPtr hfsObj, AEDesc *fileSpecifier)
  209. {
  210.     OSErr        err;
  211.     AEDesc        nullDesc, hfsData;
  212.     AliasHandle    fileAlias;
  213.  
  214.     //
  215.     // Create the file descriptor with the FSSpec passed in.
  216.     //
  217.     err = NewAlias(NULL, hfsObj, &fileAlias);
  218.     require(err == noErr, NewAlias);
  219.  
  220.     HLock((Handle) fileAlias);
  221.     err = AECreateDesc(typeAlias, (Ptr) *fileAlias, 
  222.                 GetHandleSize((Handle) fileAlias), &hfsData);
  223.     HUnlock((Handle) fileAlias);
  224.     DisposeHandle((Handle) fileAlias);
  225.     require(err == noErr, AECreateDesc);
  226.  
  227.     //
  228.     // Make the object specifier with a null container
  229.     // (i.e., "file of <null>", or just "file")
  230.     //
  231.     nullDesc.descriptorType = typeNull;
  232.     nullDesc.dataHandle = NULL;    
  233.     err = CreateObjSpecifier(typeWildCard, &nullDesc, 
  234.                 formAlias, &hfsData, false, fileSpecifier);
  235.  
  236. AECreateDesc:
  237. NewAlias:
  238.     return err;
  239. }
  240.  
  241. //----------------------------------------------------------------------------
  242. // MakePropertySpecifierForSpecifier
  243. //----------------------------------------------------------------------------
  244.  
  245. static pascal OSErr MakePropertySpecifierForSpecifier
  246.     (DescType property, AEDesc *ofSpecifier, AEDesc *propertySpecifier)
  247. {
  248.     OSErr        err;
  249.     AEDesc        keyData;
  250.     
  251.     //
  252.     // Create a 'type' AEDesc with the desired property
  253.     //
  254.     err = AECreateDesc(typeType, (Ptr) &property, sizeof(DescType), &keyData);
  255.     require(err == noErr, AECreateDesc);
  256.  
  257.     //
  258.     // With it create a property specifier for the object specifier
  259.     // passed to us.
  260.     //
  261.     err = CreateObjSpecifier(cProperty, ofSpecifier, 
  262.                 formPropertyID, &keyData, false, propertySpecifier);
  263.  
  264.     (void) AEDisposeDesc(&keyData);    
  265. AECreateDesc:
  266.     return err;
  267. }
  268.  
  269. //----------------------------------------------------------------------------
  270. // GetSizeFromIconType
  271. //----------------------------------------------------------------------------
  272.  
  273. static pascal Size GetSizeFromIconType (DescType iconType)
  274. {
  275.     Size    size = -1;
  276.  
  277.     switch (iconType) {
  278.         case large8BitData:
  279.             size = kLarge8BitIconSize;
  280.             break;
  281.         case large4BitData:
  282.             size = kLarge4BitIconSize;        
  283.             break;
  284.         case large1BitMask:
  285.             size = kLargeIconSize;
  286.             break;
  287.         case small8BitData:
  288.             size = kSmall8BitIconSize;
  289.             break;
  290.         case small4BitData:
  291.             size = kSmall4BitIconSize;
  292.             break;
  293.         case small1BitMask:
  294.             size = kSmallIconSize;
  295.             break;
  296.     }
  297.     return size;
  298. }
  299.  
  300.  
  301. //----------------------------------------------------------------------------
  302. // BuildIconSuiteFromAEDesc
  303. //
  304. // OK, this uses the Apple Event Manager to pick the icon data out of the
  305. // 'ifam' AEDesc.
  306. //----------------------------------------------------------------------------
  307.  
  308. static pascal OSErr BuildIconSuiteFromAEDesc
  309.     (Boolean largeIcons, Handle *iconSuite, AEDesc *iconFam)
  310. {
  311.     OSErr        err;
  312.     Handle         suite, icon;
  313.     AERecord    rec;
  314.     Ptr            buffer;
  315.     DescType    large[3] = {large8BitData, large4BitData, large1BitMask};
  316.     DescType    small[3] = {small8BitData, small4BitData, small1BitMask};
  317.     DescType    *type, iconType, typeCode;
  318.     long        count;
  319.     Size        maxSize, size, iconSize;
  320.     Boolean        maskAdded;
  321.     DescType    maskType;
  322.  
  323.     maskAdded = false;
  324.     suite = NULL;
  325.     maxSize = kLarge8BitIconSize;
  326.  
  327.     if (largeIcons == true) {
  328.         type = large;
  329.         maskType = large1BitMask;
  330.     }
  331.     else {
  332.         type = small;
  333.         maskType = small1BitMask;
  334.     }
  335.  
  336.     buffer = NewPtr(maxSize);
  337.     require(buffer != NULL, NewPtr);
  338.     
  339.     err = NewIconSuite(&suite);
  340.     require(err == noErr, NewIconSuite);
  341.     
  342.     err = AECoerceDesc(iconFam, typeAERecord, (AEDesc *) &rec);
  343.     require(err == noErr, AECoerceDesc);
  344.     
  345.     for (count = 0; count < 3; count ++) {
  346.         //
  347.         // loop through the icons and grab the data from the AERecord for
  348.         // each type of icon we're interested in.
  349.         //
  350.         iconType = type[count];
  351.         size = GetSizeFromIconType(iconType);
  352.         err = AEGetKeyPtr(&rec, iconType, iconType, &typeCode, 
  353.                         buffer, maxSize, &iconSize);
  354.     
  355.         if (err == noErr) {
  356.             //
  357.             // We don't set the error code for this unless the NewHandle
  358.             // call fails, because it's possible that the 'ifam' doesn't
  359.             // have an icon for one that we're interested in.
  360.             //
  361.             icon = NewHandle(size);
  362.     
  363.             if (icon != NULL) {
  364.                 //
  365.                 // OK, the memory alloc succeeded and we have data. Copy
  366.                 // it into the allocated icon and add it to the suite. 
  367.                 // Set atLeastOne to true, to indicate later that we did
  368.                 // in fact add at least one icon to this suite.
  369.                 //
  370.                 BlockMoveData(buffer, *icon, size);
  371.                 err = AddIconToSuite(icon, suite, iconType);
  372.                 if ((err == noErr) && (iconType == maskType))
  373.                     maskAdded = true;
  374.             }
  375.             else
  376.                 err = memFullErr;
  377.         }
  378.     }
  379.  
  380.     (void) AEDisposeDesc(&rec);
  381.  
  382. AECoerceDesc:
  383.     if ((err != noErr) || (maskAdded == false)) {
  384.         //
  385.         // There was either an error in a memory allocation,  or something
  386.         // else went wrong (like no mask was added to the suite).  Get
  387.         // rid of the partially created suite.
  388.         //
  389.         DisposeIconSuite(suite, true);
  390.         suite = NULL;
  391.     }
  392.  
  393. NewIconSuite:
  394.     DisposePtr(buffer);
  395.  
  396. NewPtr:
  397.     *iconSuite = suite;
  398.     return err;
  399. }
  400.  
  401. //----------------------------------------------------------------------------
  402. // GetIconSuiteFromFinder
  403. //
  404. // Send a GetData AE for the 'ifam'
  405. //----------------------------------------------------------------------------
  406. OSErr GetIconSuiteFromFinder (FSSpecPtr hfsObj, Handle *iconSuite)
  407. {
  408.     OSErr        err;
  409.     AppleEvent    finderEvent, replyEvent;
  410.     AEDesc        fileSpecifier, iconPropertySpecifier;
  411.     DescType    returnType;
  412.     Size        returnSize;
  413.     long        returnLong;
  414.     AEDesc        iconFamily;
  415.  
  416.     //
  417.     // Set up our locals for easy cleanup
  418.     //
  419.     *iconSuite = NULL;
  420.  
  421.     //
  422.     // Make sure the Finder is scriptable and is running.
  423.     //
  424.     err = paramErr;
  425.     require(HaveScriptableFinder() == true, HaveScriptableFinder);
  426.  
  427.     //
  428.     // Make a GetData Apple event to send to the Finder
  429.     //
  430.     err = MakeAppleEvent(kAECoreSuite, kAEGetData, &pFinderTarget, 
  431.                 &finderEvent);
  432.     require(err == noErr, MakeAppleEvent);
  433.     
  434.     //
  435.     // Make an object specifier for the interesting file
  436.     //
  437.     err = MakeSpecifierForFile(hfsObj, &fileSpecifier);
  438.     require(err == noErr, MakeSpecifierForFile);
  439.     
  440.     //
  441.     // Make an icon family property specifier for the file
  442.     //
  443.     err = MakePropertySpecifierForSpecifier(pIconBitmap, &fileSpecifier, 
  444.                 &iconPropertySpecifier);
  445.     require(err == noErr, MakePropertySpecifierForSpecifier);
  446.     
  447.     //
  448.     // Stuff it in the Apple event and send it
  449.     //
  450.     err = AEPutParamDesc(&finderEvent, keyDirectObject, &iconPropertySpecifier);
  451.     require(err == noErr, AEPutParamDesc);
  452.  
  453.     err = SendAppleEvent(&finderEvent, &replyEvent,
  454.                 kAEWaitReply + kAECanInteract + kAECanSwitchLayer);
  455.     require(err == noErr, SendAppleEvent);
  456.     
  457.     //
  458.     // Now the Finder may have sent us an error number
  459.     //
  460.     err = AEGetParamPtr(&replyEvent, keyErrorNumber, typeLongInteger, 
  461.                         &returnType, &returnLong, sizeof(long), &returnSize);
  462.  
  463.     if (err == noErr)
  464.         err = (OSErr) returnLong;
  465.     else if (err == errAEDescNotFound)
  466.         err = noErr;
  467.  
  468.     //
  469.     // If not, get the icon family and build an icon suite
  470.     //
  471.  
  472.     if (!err)
  473.     {        
  474.         err = AEGetParamDesc(&replyEvent, keyDirectObject, typeWildCard, &iconFamily);    
  475.         require(err == noErr, AEGetParamDesc);
  476.         err = BuildIconSuiteFromAEDesc(true, iconSuite, &iconFamily);
  477.     }
  478.  
  479.     //
  480.     // Clean up and exit
  481.     //
  482.  
  483.     (void) AEDisposeDesc(&iconFamily);
  484.  
  485. AEGetParamDesc:
  486.     (void) AEDisposeDesc(&replyEvent);
  487.  
  488. SendAppleEvent:
  489. AEPutParamDesc:
  490.     (void) AEDisposeDesc(&iconPropertySpecifier);
  491.  
  492. MakePropertySpecifierForSpecifier:
  493.     (void) AEDisposeDesc(&fileSpecifier);
  494.  
  495. MakeSpecifierForFile:
  496.     (void) AEDisposeDesc(&finderEvent);
  497.  
  498. MakeAppleEvent:
  499. HaveScriptableFinder:
  500.     return err;
  501. }
  502.